/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * GUI.java
 *
 * Created on 06/02/2010, 21:32:39
 */

package multiversiacliente;

import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;
import com.mysql.jdbc.ResultSetMetaData;
import com.mysql.jdbc.Statement;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Dimension2D;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import sun.awt.windows.ThemeReader;

/**
 *
 * @author sabiotriste
 */
public class GUI extends javax.swing.JFrame {

    enum EstrategiaPersistencia{
        NAIVE_SOLUTION, DISTANCE_BASED, SNAPSHORT
    }

    EstrategiaPersistencia strategiaPersistencia;

    enum TileType{
        GRAMA, PEDRA, AGUA, ITEM
    }

    enum Classes{
        ORC
    }

    class Tile{

        public int x;
        public int y;
        public TileType tipo;
        public boolean andavel;

        /* Necessário para o A* */
        
        public int      G; /* MOVER DO INÍCIO ATÉ ESTE PONTO */
        public int      H; /* MOVER DESTE PONTO ATÉ O FINAL  */
        public float    F; /* G + H */

    }



    static int avatarId=0;

    class Avatar implements Runnable{

        public int idAvatar;
        public ImageIcon icone;
        public JLabel label;
        public int x,y;
        public boolean movendo = false;


        Border paddingBorder = BorderFactory.createEmptyBorder(10,10,10,10);
        Border border = BorderFactory.createLineBorder(Color.DARK_GRAY);
        Border pegouItem = BorderFactory.createLineBorder(Color.BLUE);


        public Avatar( ){
            
        }

        public Tile getTile( int x, int y ){
            
            return mapa.get ( labels[x][y] );

        }

        public void pathFinder(Tile inicio, Tile fim) throws InterruptedException{
            
//            trace ( String.format("O destino é %d:%d\n", fim.x, fim.y));

//            labels[ fim.x ][ fim.y ].setBackground( new Color(0,200,0) );
//            labels[ fim.x ][ fim.y ].setIcon( null );

   
            int F, G, H;
            boolean tiles[][] = new boolean[20][20];
            for( int i=0; i<20; i++)
                for(int j=0; j<20; j++)
                    tiles[i][j] = true;
            
  

            // Mantêm uma lista aberta de Tiles
            ArrayList<Tile> listaAberta = new ArrayList<Tile>();

            Tile __t ;

            int xAnterior = inicio.x;
            int yAnterior = inicio.y;


            for( int i=0 ; i<100; i++){

                x = inicio.x;
                y = inicio.y;


                
                /* Fecha o nó atual */
                tiles[ inicio.x ][ inicio.y ] = false;

                listaAberta = new ArrayList<Tile>();

                if ( inicio.equals(fim))
                    break;

//                trace( String.format("Começando de Tile(%d,%d) até Tile(%d,%d)\n ", inicio.x, inicio.y, fim.x, fim.y ));

                /* Para cima */
                if ( inicio.y > 0 ){

                    /* Se é acessível */
                    __t = getTile(x, y-1);
                    if ( __t.andavel && tiles[ x ][ y-1 ] ){

                        tiles[ x ][ y-1 ] = false;

                        /* Calculando o G */
                        __t.G = inicio.G + 10;

                        /* Estimando H */
                        __t.G = 10 * (Math.abs( (__t.x - fim.x) ) + Math.abs( (__t.y - fim.y) ));

                        /* Calculando F */
                        __t.F = __t.G + __t.H;

                        /* Colocando na lista aberta */
                        listaAberta.add(__t);

//                        labels[x][y-1].setBackground( new Color( 0,200,0 ));
//                        labels[x][y-1].setIcon( null );

                    }
                }

                /* Para baixo */
                if ( inicio.y < 19 && tiles[ x ][ y+1 ]  ){

                    /* Se é acessível */
                    __t = getTile(x, y+1);
                    if ( __t.andavel ){

                        tiles[ x ][ y+1 ] = false;

                        /* Calculando o G */
                        __t.G = inicio.G + 10;

                        /* Estimando H */
                        __t.G = 10 * (Math.abs( (__t.x - fim.x) ) + Math.abs( (__t.y - fim.y) ));

                        /* Calculando F */
                        __t.F = __t.G + __t.H;

                        /* Colocando na lista aberta */
                        listaAberta.add(__t);


//                        labels[x][y+1].setBackground( new Color( 0,200,0 ));
//                        labels[x][y+1].setIcon( null );
                    }


                }

                /* Para o lado direito */
                if ( inicio.x > 0  && tiles[ x-1 ][ y ]  ){

                    /* Se é acessível */
                    __t = getTile(x-1, y);
                    if ( __t.andavel ){

                        tiles[ x-1 ][ y ] = false;

                                            /* Calculando o G */
                        __t.G = inicio.G + 10;

                        /* Estimando H */
                        __t.G = 10 * (Math.abs( (__t.x - fim.x) ) + Math.abs( (__t.y - fim.y) ));

                        /* Calculando F */
                        __t.F = __t.G + __t.H;

                        /* Colocando na lista aberta */
                        listaAberta.add(__t);

//                        labels[x-1][y].setBackground( new Color( 0,200,0 ));
//                        labels[x-1][y].setIcon( null );

                    }


                }

                /* Para o lado esquerdo */
                if ( inicio.x < 19 && tiles[ x+1 ][ y ]  ){

                    /* Se é acessível */
                    __t = getTile(x+1, y);
                    if ( __t.andavel ){

                        tiles[ x+1 ][ y ] = false;

                                            /* Calculando o G */
                        __t.G = inicio.G + 10;

                        /* Estimando H */
                        __t.G = 10 * (Math.abs( (__t.x - fim.x) ) + Math.abs( (__t.y - fim.y) ));

                        /* Calculando F */
                        __t.F = __t.G + __t.H;

                        /* Colocando na lista aberta */
                        listaAberta.add(__t);

//                        labels[x+1][y].setBackground( new Color( 0,200,0 ));
//                        labels[x+1][y].setIcon( null );
                    }


                }



                for( Tile t: listaAberta){
//                    trace ( String.format("Tile (%d,%d) : F (%f) = G (%d) + H (%d)  \n", t.x, t.y, t.F , t.G , t.H ) );
                }

                /* Agora vai escolher o menor */
                int menor = Integer.MAX_VALUE;

                __t = new Tile();

                for ( Tile t: listaAberta ){

                    if (t.F < menor){
                        menor = (int) t.F;
                        __t = t;
                    }

//                    trace ( String.format("O menor até agora é Tile(%d,%d) = %d", __t.x, __t.y, menor));
                }


//                trace ( String.format("Escolheu o Tile(%d,%d) como o menor, agora feche este.", __t.x, __t.y) );

                tiles[ __t.x ][ __t.y ] = false;

                /* Marca a menor escolhida */
                labels[ __t.x ][ __t.y ].setIcon( orc );
                labels[ __t.x ][ __t.y ].setBackground( new Color(0,150, 0) );



                /* Coloca o que estava antes */
                switch( mapa.get(labels[ inicio.x ][ inicio. y ]).tipo ){
                    case GRAMA:
                            labels[ inicio.x ][ inicio.y ].setIcon( grama );
                        break;

                    case ITEM:
                            labels[ inicio.x ][ inicio.y ].setIcon( grama );
                        break;


                    case PEDRA:
                            labels[ inicio.x ][ inicio.y ].setIcon( pedra );
                        break;
                }

                /* Se pegou um item */
                if ( mapa.get( labels[inicio.x][inicio.y] ).tipo == TileType.ITEM ){
//                    labels[ inicio.x ][ inicio.y ].setBackground( new Color(0,0,255) );
                    //labels[ inicio.x ][ inicio.y ].setIcon(orc);
                    mapa.get( labels[inicio.x][inicio.y] ).tipo = TileType.GRAMA;
                    //labels[ inicio.x ][ inicio.y ].setBorder( BorderFactory.createCompoundBorder( pegouItem ,paddingBorder ) );
                }


                /* Inicia da menor escolhida */
                inicio = getTile( __t.x ,  __t.y) ;

                if( Math.abs( x - xAnterior ) >= 3 || Math.abs( y - yAnterior) >= 3 ){
                    s.moverAvatar( this.idAvatar, x, y );
                    xAnterior = x;
                    yAnterior = y;
                    //labels[ inicio.x ][ inicio.y ].setBackground( new Color(255,0,0) );
                    //labels[ inicio.x ][ inicio.y ].setIcon(orc);
                    //labels[ inicio.x ][ inicio.y ].setBorder( BorderFactory.createCompoundBorder(border,paddingBorder ) );
                }

        



                try{
                    Thread.sleep( 200 );
                }catch( InterruptedException ex){}

                labels[ x ][ y ].setBackground( new Color(0,150,0) );
                labels[ x ][ y ].setBorder(null);

                

            }

        }

        public void run(){

                int __x,__y;

                Icon orc = new ImageIcon( getClass().getResource("imagens/orc.gif") );

                Random r = new Random();

                /* Escolhe um ponto aleatório no mapa para colocar o ORC */

                Tile t;
                JLabel l;
                do{
                    x =  r.nextInt(19);
                    y =  r.nextInt(19);
                    l = labels[ x ][ y ];
                    t = mapa.get( l );

                    /* Não pode colocar o ORC na água */
                }while ( t.tipo != TileType.PEDRA && t.tipo != TileType.GRAMA );


                /* Persiste o Avatar */
                this.idAvatar = s.criarAvatar( String.format("Avatar%d", new Random().nextInt(1000) ) , x , y );
                


                /* Agora coloca o ORC, mas... mantém o tipo do Tile */
                l.setIcon( orc );

                /* Agora sorteia um ponto aleatório na tela e manda vê. */



               try{
                   while(true){

                       do{

                           __x =  r.nextInt(19);
                           __y =  r.nextInt(19);

                            l = labels[ __x ][ __y ];
                            t = mapa.get( l );

                            /* Não pode colocar o ORC na água */
                        }while ( t.tipo != TileType.PEDRA && t.tipo != TileType.GRAMA );


                        /* Volta o Tile que estava antes */
                        if (  mapa.get( labels[x][y] ).tipo == TileType.GRAMA ){
                            labels[x][y].setIcon( grama  );
                        }else if ( mapa.get( labels[x][y] ).tipo == TileType.PEDRA ){
                            labels[x][y].setIcon(pedra);
                        }

                        pathFinder( getTile(x,y) , getTile(__x,__y));

                       /* Define o icone do orc no novo label */
                       l.setIcon( orc );
                       x = __x;
                       y = __y;


                       Thread.sleep( new Random().nextInt(1000) );
                       

                   }
               }catch( InterruptedException ex){
                   
               }
        }


    }



    /** Classe de Persistência no Banco */
    public class ServidorMMOG implements Runnable{

        private Connection connection 	= null;
        private Statement  statement	= null;

        PreparedStatement moverAvatar;
        PreparedStatement criarAvatar;

        public ServidorMMOG(){

            String JDBC_DRIVER 		= "com.mysql.jdbc.Driver";
            String DATABASE_URL     = "jdbc:mysql://127.0.0.1/Multiversia";

            try{

                Class.forName(JDBC_DRIVER );
                connection 			= (Connection) DriverManager.getConnection(DATABASE_URL, "root", "123");
                statement			= (Statement) connection.createStatement();

            }catch(SQLException sqlex){

                System.out.println("Exceção lançada: SQLException." + sqlex.getMessage() );

            }catch(ClassNotFoundException classNotFoundException){

                System.out.println("Exceção lançada: ClassNotFoundException.");

            }
            try {
                /* Preparando as consultas */

                /* A de mover o avatar */
                moverAvatar = (PreparedStatement) connection.prepareStatement(" UPDATE Avatar SET x = ?, y = ? WHERE idAvatar = ? ");

                /* A de criar um avatar */
                criarAvatar = (PreparedStatement) connection.prepareStatement( "INSERT INTO Avatar(nickname,x,y,Conta_idConta) VALUES( ?, ?, ?,1) " , PreparedStatement.RETURN_GENERATED_KEYS );

            } catch (SQLException ex) {
                System.out.println("Alguma coisa saiu errados nas declarações preparadas.");
            }


        }

        public void run(){
            
        }

        public synchronized  int criarAvatar( String nickname, int x, int y ){
            int idAvatar = 0;

            log( String.format("Adicionando Avatar(%s, %d, %d) ", nickname, x, y) );

            try{

                criarAvatar.setString(1, nickname);
                criarAvatar.setInt(2, x);
                criarAvatar.setInt(3, y);
                criarAvatar.execute();

                ResultSet keys = criarAvatar.getGeneratedKeys();
                keys.next();
                idAvatar = keys.getInt(1);

                log( new String( String.format("Criado Avatar %s com o id %d\n", nickname, idAvatar)) );

            }catch( SQLException sqlex ){
                // Faz nada
                log(" SQLException:  " + sqlex.getMessage() );

            }

            return idAvatar;
        }

        public boolean moverAvatar( int idAvatar, int x, int y){
            
            try {


                moverAvatar.setInt(1, x);
                moverAvatar.setInt(2, y);
                moverAvatar.setInt(3, idAvatar);


                log( String.format("Avatar%d movendo-se para %d:%d\n", idAvatar, x, y) );

                moverAvatar.executeUpdate();

            } catch (SQLException ex) {
                System.out.println("SQLException: "+ ex.getMessage());
            }


            return false;
        }

    }

    Tile mapaTiled[][] = new Tile[20][20];


    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        barraDeFerramentas = new javax.swing.JToolBar();
        jButton1 = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();
        jButton3 = new javax.swing.JButton();
        painelLateral = new javax.swing.JPanel();
        labelNAvatares = new javax.swing.JLabel();
        nAvatares = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        estrategiaDePersistencia = new javax.swing.JComboBox();
        jTextField1 = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();
        butaoAplicar = new javax.swing.JButton();
        jSlider1 = new javax.swing.JSlider();
        jLabel5 = new javax.swing.JLabel();
        jLabel6 = new javax.swing.JLabel();
        jLabel7 = new javax.swing.JLabel();
        jPanel2 = new javax.swing.JPanel();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        mundoVirtual = new javax.swing.JPanel();
        jPanel4 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();
        jTabbedPane2 = new javax.swing.JTabbedPane();
        jTabbedPane3 = new javax.swing.JTabbedPane();
        jTabbedPane4 = new javax.swing.JTabbedPane();
        jPanel1 = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        textLog = new javax.swing.JTextArea();
        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setResizable(false);

        barraDeFerramentas.setFloatable(false);
        barraDeFerramentas.setRollover(true);

        jButton1.setText("Play");
        jButton1.setFocusable(false);
        jButton1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jButton1.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        barraDeFerramentas.add(jButton1);

        jButton2.setText("Pausar");
        jButton2.setFocusable(false);
        jButton2.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jButton2.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        barraDeFerramentas.add(jButton2);

        jButton3.setText("Próximo Passo");
        jButton3.setFocusable(false);
        jButton3.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jButton3.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        barraDeFerramentas.add(jButton3);

        labelNAvatares.setFont(new java.awt.Font("DejaVu Sans", 1, 13));
        labelNAvatares.setForeground(new java.awt.Color(41, 74, 203));
        labelNAvatares.setText("N. Avatares");

        nAvatares.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                nAvataresActionPerformed(evt);
            }
        });
        nAvatares.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                nAvataresKeyReleased(evt);
            }
        });

        jLabel2.setFont(new java.awt.Font("DejaVu Sans", 1, 13));
        jLabel2.setForeground(new java.awt.Color(41, 74, 203));
        jLabel2.setText("Estratégia de Persistência");

        jLabel4.setFont(new java.awt.Font("DejaVu Sans", 1, 13));
        jLabel4.setForeground(new java.awt.Color(41, 74, 203));
        jLabel4.setText("Latência de Rede");

        estrategiaDePersistencia.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Nayve Solution", "Time Based", "SnapShot", "Distance Based" }));
        estrategiaDePersistencia.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                estrategiaDePersistenciaItemStateChanged(evt);
            }
        });
        estrategiaDePersistencia.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                estrategiaDePersistenciaActionPerformed(evt);
            }
        });

        jLabel1.setText("ms");

        butaoAplicar.setText("Aplicar");

        jLabel5.setText("Nenhum");

        jLabel6.setText("Elevado");

        jLabel7.setFont(new java.awt.Font("DejaVu Sans", 1, 13));
        jLabel7.setForeground(new java.awt.Color(41, 74, 203));
        jLabel7.setText("Spawning de Itens");

        javax.swing.GroupLayout painelLateralLayout = new javax.swing.GroupLayout(painelLateral);
        painelLateral.setLayout(painelLateralLayout);
        painelLateralLayout.setHorizontalGroup(
            painelLateralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(painelLateralLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(painelLateralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(nAvatares, javax.swing.GroupLayout.DEFAULT_SIZE, 223, Short.MAX_VALUE)
                    .addComponent(labelNAvatares)
                    .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 223, Short.MAX_VALUE)
                    .addComponent(estrategiaDePersistencia, 0, 223, Short.MAX_VALUE)
                    .addGroup(painelLateralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                        .addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, 139, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGroup(painelLateralLayout.createSequentialGroup()
                            .addGroup(painelLateralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                                .addComponent(jTextField1)
                                .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(butaoAplicar))
                            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                            .addComponent(jLabel1))))
                .addContainerGap())
            .addGroup(painelLateralLayout.createSequentialGroup()
                .addComponent(jLabel5)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 104, Short.MAX_VALUE)
                .addComponent(jLabel6)
                .addGap(38, 38, 38))
            .addGroup(painelLateralLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel7, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGap(98, 98, 98))
        );
        painelLateralLayout.setVerticalGroup(
            painelLateralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(painelLateralLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(labelNAvatares)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(nAvatares, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(estrategiaDePersistencia, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addComponent(jLabel4)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(painelLateralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel1))
                .addGap(25, 25, 25)
                .addComponent(jLabel7)
                .addGap(18, 18, 18)
                .addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(painelLateralLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel5, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel6))
                .addGap(118, 118, 118)
                .addComponent(butaoAplicar)
                .addContainerGap(602, Short.MAX_VALUE))
        );

        mundoVirtual.setForeground(new java.awt.Color(129, 167, 138));
        jTabbedPane1.addTab("Mundo Virtual", mundoVirtual);

        jTable1.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        jScrollPane1.setViewportView(jTable1);

        javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4);
        jPanel4.setLayout(jPanel4Layout);
        jPanel4Layout.setHorizontalGroup(
            jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel4Layout.createSequentialGroup()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 732, Short.MAX_VALUE)
                .addContainerGap())
        );
        jPanel4Layout.setVerticalGroup(
            jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel4Layout.createSequentialGroup()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 402, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(619, Short.MAX_VALUE))
        );

        jTabbedPane1.addTab("Cache", jPanel4);
        jTabbedPane1.addTab("Estado no Servidor", jTabbedPane2);
        jTabbedPane1.addTab("Requições", jTabbedPane3);
        jTabbedPane1.addTab("Gráfico de Operações", jTabbedPane4);

        textLog.setColumns(20);
        textLog.setRows(5);
        jScrollPane2.setViewportView(textLog);

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 720, Short.MAX_VALUE)
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 597, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(412, Short.MAX_VALUE))
        );

        jTabbedPane1.addTab("Log", jPanel1);

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 756, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(556, Short.MAX_VALUE))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 1064, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jMenu1.setText("Ambiente");
        jMenuBar1.add(jMenu1);

        setJMenuBar(jMenuBar1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(barraDeFerramentas, javax.swing.GroupLayout.DEFAULT_SIZE, 1589, Short.MAX_VALUE)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(painelLateral, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(barraDeFerramentas, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(painelLateral, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    private void estrategiaDePersistenciaActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_estrategiaDePersistenciaActionPerformed
        // TODO add your handling code here:
        JComboBox _j = (JComboBox) evt.getSource();
        trace( _j.getSelectedIndex() );
    }//GEN-LAST:event_estrategiaDePersistenciaActionPerformed

    private void estrategiaDePersistenciaItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_estrategiaDePersistenciaItemStateChanged
        // TODO add your handling code here:
    }//GEN-LAST:event_estrategiaDePersistenciaItemStateChanged

    private void nAvataresKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_nAvataresKeyReleased
        // TODO add your handling code here:

        JOptionPane.showMessageDialog(this, "Olá Vc");
}//GEN-LAST:event_nAvataresKeyReleased

    private void nAvataresActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nAvataresActionPerformed
        // TODO add your handling code here:
}//GEN-LAST:event_nAvataresActionPerformed

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                GUI g = new GUI();
                g.setVisible(true);
                g.trace("Aqui!!!");
            }
        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JToolBar barraDeFerramentas;
    private javax.swing.JButton butaoAplicar;
    private javax.swing.JComboBox estrategiaDePersistencia;
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JSlider jSlider1;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JTabbedPane jTabbedPane2;
    private javax.swing.JTabbedPane jTabbedPane3;
    private javax.swing.JTabbedPane jTabbedPane4;
    private javax.swing.JTable jTable1;
    private javax.swing.JTextField jTextField1;
    private javax.swing.JLabel labelNAvatares;
    private javax.swing.JPanel mundoVirtual;
    private javax.swing.JTextField nAvatares;
    private javax.swing.JPanel painelLateral;
    private javax.swing.JTextArea textLog;
    // End of variables declaration//GEN-END:variables

    JPanel palco = new JPanel();

    public Tile[] pathfinder( Tile tOrigem, Tile Destino ){

        //
        ArrayList <Tile> tileList = new ArrayList<Tile>();


        Tile[] t = new Tile[ tileList.size() ];
        return tileList.toArray(t);

    }
    
    int i,j;
    int i_atual, j_atual;
    int i_destino, j_destino;

    private void trace ( Object o ){

        System.out.println ( o.toString() );

    }

    HashMap<JLabel,Tile> mapa = new HashMap<JLabel,Tile>();
    JLabel labels[][] = new JLabel[20][20];

    /**
     * Lista de Itens possíveis
     */
    String itensSRC[] = {"shovel.gif" , "lifefluid.gif", "emerald.gif", "miracleherb.gif","syrupofhealth.gif","strongmanafluid.gif","nut.gif"};


    /**
     * Lista de Classes possíveis     * 
     */
    String classes[] = { "orc.gif" };

    public Icon grama = new ImageIcon( getClass().getResource("imagens/grass.jpeg") );
    public Icon pedra = new ImageIcon( getClass().getResource("imagens/rock.jpeg") );
    public Icon agua = new ImageIcon( getClass().getResource("imagens/water.jpeg") );
    public Icon orc   = new ImageIcon( getClass().getResource("imagens/orc.gif"));


    /**
     * Roda uma thread para lançar ítens no ambiente.
     */
    private void spawningItems(){        

        
    }



    private void criarTabuleiro(){

        GridLayout grid = new GridLayout(20,20);
        palco.setLayout( grid );

      


        for(  i=0; i<20; i++){

            for( j=0; j<20; j++){

                labels[i][j] = new JLabel();
                
                Tile q = new Tile();
                q.x = i;
                q.y = j;
                q.tipo = TileType.GRAMA;
                q.andavel = true;

//                mapaTiled[i][j] = q.;

               


                Icon icone =  grama ;

                //labels[i][j].setBackground(Color.GREEN );
                labels[i][j].setIcon( icone );
                labels[i][j].setOpaque(true);
//                labels[i][j].setText( String.format("%d  %d", i, j) );
                labels[i][j].setPreferredSize( new Dimension(30, 30));

                labels[i][j].addMouseListener(new MouseListener() {

                    public void mouseClicked(MouseEvent arg0) {
                        
                        Tile q = mapa.get( (JLabel) arg0.getSource() );
                        trace( String.format("Clicado no quadrado x:%d  y:%d TypeTile: %s", q.x, q.y, q.tipo) );

                    }

                    public void mousePressed(MouseEvent arg0) {

                    }

                    public void mouseReleased(MouseEvent arg0) {


                    }

                    public void mouseEntered(MouseEvent arg0) {
                       JLabel j = (JLabel) arg0.getSource();
                       j.setBackground( new Color(0, 200, 0) );
                    }

                    public void mouseExited(MouseEvent arg0) {
                       JLabel j = (JLabel) arg0.getSource();
                       j.setBackground( Color.GREEN );
                    }
                });

                JLabel __jl = new JLabel("In");
                __jl.setVisible(true);
                labels[i][j].add( __jl );

                

                labels[i][j].setVisible(true);
                palco.add( labels[i][j] );
                mapa.put(labels[i][j], q);
            }       


        }


        /* Preenchendo com Água */
        for (int _j=2; _j<20; _j++){
            labels[0][_j].setIcon( new ImageIcon( getClass().getResource("imagens/water.jpeg") ) );
            Tile q = mapa.get(labels[0][_j]);
            q.tipo = TileType.AGUA;
            q.andavel = false;
        }

        for( int __i=0; __i<20; __i++){            
            labels[__i][10].setIcon( new ImageIcon( getClass().getResource("imagens/water.jpeg") ) );
            Tile q = mapa.get(labels[__i][10]);
            q.tipo = TileType.AGUA;
            q.andavel = false;
        }


        if(true){
            labels[5][9].setIcon(new ImageIcon( getClass().getResource("imagens/rock.jpeg") ) );
            Tile q = mapa.get(labels[5][9]);
            q.tipo = TileType.PEDRA;
            q.andavel = true;
        }

        if(true){
            labels[5][10].setIcon(new ImageIcon( getClass().getResource("imagens/rock.jpeg") ) );
            Tile q = mapa.get(labels[5][10]);
            q.tipo = TileType.PEDRA;
            q.andavel = true;
        }

        if(true){
            labels[5][11].setIcon(new ImageIcon( getClass().getResource("imagens/rock.jpeg") ) );
            Tile q = mapa.get(labels[5][11]);
            q.tipo = TileType.PEDRA;
            q.andavel = true;
        }



        /* OUTRA PONTE */

        if(true){
            labels[15][9].setIcon(new ImageIcon( getClass().getResource("imagens/rock.jpeg") ) );
            Tile q = mapa.get(labels[15][9]);
            q.tipo = TileType.PEDRA;
            q.andavel = true;
        }

        if(true){
            labels[15][10].setIcon(new ImageIcon( getClass().getResource("imagens/rock.jpeg") ) );
            Tile q = mapa.get(labels[15][10]);
            q.tipo = TileType.PEDRA;
            q.andavel = true;
        }

        if(true){
            labels[15][11].setIcon(new ImageIcon( getClass().getResource("imagens/rock.jpeg") ) );
            Tile q = mapa.get(labels[15][11]);
            q.tipo = TileType.PEDRA;
            q.andavel = true;
        }



        if(true){
            labels[5][8].setIcon( agua  );
            Tile q = mapa.get(labels[5][8]);
            q.tipo = TileType.AGUA;
            q.andavel = false;
        }

        if(true){
            labels[4][8].setIcon( agua  );
            Tile q = mapa.get(labels[4][8]);
            q.tipo = TileType.AGUA;
            q.andavel = false;
        }

        if(true){
            labels[5][7].setIcon( agua  );
            Tile q = mapa.get(labels[5][7]);
            q.tipo = TileType.AGUA;
            q.andavel = false;
        }

        mundoVirtual.add( palco );
        mundoVirtual.setVisible(true);


        


        trace("Adicionou todos os quadros.");

    }


    private void adicionarAvatar(int i, int j){
        labels[i][j].setIcon( new ImageIcon(getClass().getResource("imagens/orc.gif")) );
    }

    private void log( Object obj ){

        this.textLog.append( obj.toString() + "\n" );

    }


    ServidorMMOG s = new ServidorMMOG();

    /* Definir Estratégia de Persistência */
    public void setEstrategiaPersistencia( EstrategiaPersistencia estrategiaPersistencia ){
        this.estrategiaDePersistencia = estrategiaDePersistencia;
    }

    /** Creates new form GUI */
    public GUI() {
        
       initComponents();
       setPreferredSize( new Dimension(1024,768));
       setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

       log( new String("Log Iniciado"));

       // Construíndo Tabuleiros com o TileSet Definido
       criarTabuleiro();
       
       pack();
       setResizable(true);

       butaoAplicar.setIcon( new ImageIcon(getClass().getResource("icones/bullet_go.png") ));

       Avatar avatar_1 = new Avatar();
       avatar_1.idAvatar = ++avatarId;

       Avatar avatar_2 = new Avatar();
       avatar_2.idAvatar = ++avatarId;


       ExecutorService ex = Executors.newFixedThreadPool(122);
       for ( int i=0; i<2; i++){
           ex.execute( new Avatar() );
       }
  
       ex.execute( s );


       ex.execute(new Runnable() {
            public void run() {

                Random r = new Random();

                while(true){

                   System.out.println("Lançando itens no ambiente.");


                    /* Só coloca itens na grama */

                   JLabel jl;
                   Tile t;
                    do{
                         jl =  labels[ r.nextInt(19) ][ r.nextInt(19) ] ;
                         t  = mapa.get( jl );
                    }while ( t.tipo != TileType.GRAMA );

                        jl.setIcon( new ImageIcon( getClass().getResource( "itens/" + itensSRC[ r.nextInt( itensSRC.length - 1 ) ] ) ) );
                        jl.setBackground( new Color(0,150, 0) );


//                        jl.setBorder( BorderFactory.createCompoundBorder(border,paddingBorder) );

                        // Agora Tem um Item no Ambiente :)
                        t.tipo = TileType.ITEM;



                    try {
                        Thread.sleep( (long) r.nextInt(100) );
                    } catch (InterruptedException ex) {
                        // Faz nada
                    }
                }
            }
        });


//        Avatar.se

    }
}
